package com.ezlcp.commons.filter;

import com.ezlcp.commons.base.entity.JsonResult;
import com.ezlcp.commons.constant.Constants;
import com.ezlcp.commons.model.SysUser;
import com.ezlcp.commons.tool.StringUtils;
import com.ezlcp.commons.utils.ContextUtil;
import com.ezlcp.commons.utils.RequestUtil;
import com.ezlcp.commons.utils.TokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;

/**
 * @author Elwin ZHANG
 * @description: 根据token获取上下文信息 <br/>
 * @date 2023/2/1 17:04
 */
public class WebContextFilter implements HandlerInterceptor {

    /**
     * 白名单地址
     */
    private static ArrayList<String> whitelist = new ArrayList<>();

    static {
        whitelist.add("/doc.html");
        whitelist.add("/swagger-ui.html");
        whitelist.add("/swagger-resources");
        whitelist.add("/error");
        whitelist.add("/favicon.ico");
        whitelist.add("/ezlcp/user/menu/getMenuName");
        whitelist.add("/ezlcp/log/systemLog/insert");
        whitelist.add("/ezlcp/log/loginLog/insert");
        whitelist.add("/ezlcp/log/loginLog/logout");
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //跳过OPTIONS操作
        if ("OPTIONS".equals(request.getMethod())) {
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        setNoCache(response);
        String token = getTokenStr(request);
        //没有token，则失败
        if (StringUtils.isEmpty(token)) {
            String url = request.getRequestURI();
            //白名单地址跳过
            if (whitelist.contains(url) || url.startsWith("/v3/")
                    || url.startsWith("/webjars/") || url.startsWith("/druid")
                    || url.startsWith("/validCode/") || url.indexOf("/auth/") > 0
                    || url.indexOf("/test/") > 0) {
                return HandlerInterceptor.super.preHandle(request, response, handler);
            }
            responseTokenFail(JsonResult.Fail("token.noTokenParam"), response);
            return false;
        }
        //根据token取出用户信息保存到上下文中
        SysUser sysUser = TokenUtil.getUserByToken(token);
        //没取到token关联的用户
        if (sysUser == null) {
            String message = TokenUtil.getMessageByToken(token);
            //没有被挤下线的消息
            if (StringUtils.isEmpty(message)) {
                responseTokenFail(JsonResult.Fail("loginLog.autoQuit"), response);
                return false;
            }
            JsonResult result = new JsonResult();
            result.setData(message);
            result.setShow(true);
            result.setMessage("loginLog.forcedOffline");
            responseTokenFail(result, response);
            TokenUtil.removeMessage(token);
            return false;
        }
        String curIp = RequestUtil.getIpAddress(request);
        String loginIp = sysUser.getIpAddr();
        //IP地址和浏览器信息相同（为方便测试过滤localHost）
        if ("localhost".equals(loginIp) || "localhost".equals(curIp)) {
            ContextUtil.setCurrentUser(sysUser);
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        if (curIp.equals(loginIp) && sysUser.getUserAgent().equals(request.getHeader("User-Agent"))) {
            ContextUtil.setCurrentUser(sysUser);
            return HandlerInterceptor.super.preHandle(request, response, handler);
        }
        //疑似会话攻击
        responseTokenFail(JsonResult.Fail("loginLog.forcedOffline"), response);
        return false;
    }

    /***
    * @description 禁用浏览器缓存GET方法的接口
    */
    private void setNoCache(HttpServletResponse response){
        response.setHeader("Cache-Control","no-cache,no-store");
        response.setHeader("Expires","0");
        response.setHeader("ETag",String.valueOf(System.currentTimeMillis()));
        response.setHeader("Pragma","no-cache");
        response.setHeader("Date",String.valueOf(new Date()));
        response.setHeader("Last-Modified",String.valueOf(new Date()));
    }

    /***
     * @description: token校验失败后响应客户端请求
     * @param jsonResult 返回消息
     * @param response 响应对象
     * @author Elwin ZHANG
     * @date 2022/5/7 13:18
     */
    private void responseTokenFail(JsonResult jsonResult, HttpServletResponse response) throws IOException {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        //设置服务器的编码，默认是ISO-8859-1
        response.setCharacterEncoding("UTF-8");
        //告诉浏览器服务器的编码格式
        response.setContentType("application/json; charset=utf-8");
        jsonResult.setCode(HttpStatus.UNAUTHORIZED.value());
        response.getWriter().print(jsonResult);
    }

    /**
     * 根据请求头获取token值
     *
     * @param request 请求对象
     * @return 如果获取不到，则返回空字符
     */
    private String getTokenStr(HttpServletRequest request) {
        String token = request.getHeader(Constants.TOKEN);
        if (StringUtils.isNotEmpty(token)) {
            return token;
        }
        token = request.getHeader(Constants.Authorization);
        if (StringUtils.isNotEmpty(token)) {
            return token;
        }
        token = request.getParameter(Constants.TOKEN);
        if (StringUtils.isNotEmpty(token)) {
            return token;
        }
        return "";
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        ContextUtil.clearUser();
    }
}
